//masterSocket
//
//Ky Halverson

#include <iostream>
#include <stdio.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sstream>
#include <signal.h>

#define CONNECTIONS_ALLOWED 15
#define CLIENT_UDP 9876

using namespace std;

class masterSocket{

public:




//standard
masterSocket(){}

//client socket
masterSocket(const char* IPaddr, int port, string transferType)
{

  type = transferType;
  //UDP
  if (transferType == ("UDP"))
    {
	sockfd =  socket(AF_INET, SOCK_DGRAM, 0);
	memset(&socketServer,0, sizeof(socketServer));
	memset(&socketClient,0, sizeof(socketClient));

	
	socketClient.sin_family = AF_INET;
	socketClient.sin_addr.s_addr = htonl(INADDR_ANY);
	socketClient.sin_port = htons(CLIENT_UDP);

	if(bind(sockfd, (struct sockaddr *)&socketClient, sizeof(socketClient)) !=(-1))
	{
		std::cout<<"Bind complete"<<std::endl;

	}
	else
	{
		std::cout<<"Bind failed - port in use?"<<std::endl;
	}

	
	socketServer.sin_family = AF_INET;
	socketServer.sin_port = htons(port);
	inet_pton(AF_INET,IPaddr,&socketServer.sin_addr);

	std::cout<<"Setup Complete"<<std::endl;

    }
	
    //TCP
    else if (transferType == ("TCP"))
      {

	//server set

	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	memset(&socketServer,0, sizeof(socketServer));
	socketServer.sin_family = AF_INET;
	socketServer.sin_port= htons(port);
	inet_pton(AF_INET,IPaddr,&socketServer.sin_addr);


	if(connect(sockfd,(struct sockaddr*)&socketServer, sizeof(socketServer))!=(-1))
	{
		std::cout<<"Connected"<<std::endl;
		
	}
	else
	{
	       std::cout<<"ERROR:CLIENT:TCP: Could not connect"<<std::endl;
	}
       }
      //ERROR CONTROL
      else 
	{
	  std::cout<<"ERROR:CLIENT: UDP/TCP not specified"<<std::endl;
	}
}

//server socket
masterSocket(int port, string transferType)
{

 type = transferType;
  //UDP
  if (transferType == ("UDP"))
  {

	sockfd =  socket(AF_INET, SOCK_DGRAM, 0);
	memset(&socketServer,0, sizeof(socketServer));
	memset(&socketClient,0, sizeof(socketClient));

	
	socketServer.sin_family = AF_INET;
	socketServer.sin_addr.s_addr = htonl(INADDR_ANY);
	socketServer.sin_port = htons(port);

	
	socketClient.sin_family = AF_INET;
	socketClient.sin_port = htons(CLIENT_UDP);
	
	std::cout<<"Setup Complete"<<std::endl;

	if(bind(sockfd, (struct sockaddr *)&socketServer, sizeof(socketServer)) !=(-1))
	{
		std::cout<<"Bind complete"<<std::endl;

	}
	else
	{
		std::cout<<"Bind failed - port in use?"<<std::endl;
		close(sockfd);
	}

    }
    //TCP
    else if (transferType == ("TCP"))
      {
	//set

	memset(&socketClient,0, sizeof(socketClient));
	memset(&socketServer,0, sizeof(socketServer));
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	socketServer.sin_family = AF_INET;
	socketServer.sin_port= htons(port);
	socketServer.sin_addr.s_addr = htonl(INADDR_ANY);


	if(bind(sockfd,(struct sockaddr *)&socketServer, sizeof(socketServer)) != (-1))
         {
		std::cout<<"Server Binded"<<std::endl;
		if(listen(sockfd, CONNECTIONS_ALLOWED) != (-1))
		{
			std::cout<<"Listening"<<std::endl;
		}
		else
		{
			std::cout<<"ERROR:SERVER:TCP:BIND:LISTEN: Was not able to listen"<<std::endl;
		}
		

		clientAddr = (sockaddr*)&socketClient;
		fd = accept(sockfd, clientAddr, &addr_size);
		
		if (fd !=(-1))
		{
			std::cout<<"Client connected"<<std::endl;

		}
		else
		{
			std::cout<<"ERROR:SERVER:TCP:ACCEPT: Could not accept"<<std::endl;
		}
         }
	else
         {
           std::cout<<"ERROR:SERVER:TCP:Couldn't bind - port in use?"<<std::endl;
		close(sockfd);
	 }
      }
      //ERROR CONTROL
      else 
	{
	  std::cout<<"ERROR:SERVER: UDP/TCP not specified"<<std::endl;
	}
}

~masterSocket(){close(sockfd); close(fd); delete[] messageData;}



void sendIt(string host, string message)
{
 if(host =="CLIENT")
 {
  if(type == "UDP")
    {
	messageData = new char[strlen(message.c_str())];
	messageData = message.c_str();
	sendto(sockfd,(void*)messageData,strlen(message.c_str()),0,(sockaddr*)&socketServer, sizeof(socketServer));
    }
  else if(type=="TCP")
    {
	messageData = new char[strlen(message.c_str())];
	messageData = message.c_str();
	send(sockfd, (void*)messageData, strlen(message.c_str()),0);

    }
  else
  {
    std::cout<<"ERROR:SEND:type not correctly given"<< std:: endl;
  }
 }
 else if (host == "SERVER")
 {
  if(type == "UDP")
    {
	messageData = new char[strlen(message.c_str())];
	messageData = message.c_str();
	sendto(sockfd,(void*)messageData,strlen(message.c_str()),0,(sockaddr*)&socketClient, sizeof(socketClient));

    }
  else if(type=="TCP")
    {
	messageData = new char[strlen(message.c_str())];
	messageData = message.c_str();
	send(fd, (void*)messageData, strlen(message.c_str()),0);
    }
  else
  {
    std::cout<<"ERROR:SEND:type not correctly given"<< std:: endl;
  }
 }
 else
 {
  std::cout<<"ERROR:SEND: CLIENT/SERVER Not entered correctly"<< std:: endl;
 }

}


string recvIt(string host)
{
 if(host == "CLIENT")
  if(type == "UDP")
    {
	messageData = new char[6000];
	
	recvfrom(sockfd,(void*)messageData,6000,0,(sockaddr*)&socketServer,&addr_size);

	string temp= messageData;
	messageData ="";
	return temp;
    }
  else if(type=="TCP")
    {
	messageData = new char[6000];
	recv(sockfd, (void*)messageData, 6000, 0);

	string temp= messageData;
	messageData ="";
	return temp;


    }
  else
  {
    std::cout<<"ERROR:RECIEVE:type not correctly given"<< std:: endl;
  }
 else if(host == "SERVER")
 {
  if(type == "UDP")
    {
	messageData = new char[6000];
	
	recvfrom(sockfd,(void*)messageData,6000,0,(sockaddr*)&socketClient,&addr_size);

	string temp= messageData;
	messageData ="";
	return temp;
    }
  else if(type=="TCP")
    {
	messageData = new char[6000];
	recv(fd, (void*)messageData, 6000, 0);

	string temp= messageData;
	messageData="";
	return temp;


    }
  else
  {
    std::cout<<"ERROR:RECIEVE:type not correctly given"<< std:: endl;
  }
 }
 else
 {
   std::cout<<"ERROR:RECIEVE: CLIENT/SERVER Not entered correctly"<< std:: endl;
 }


}



private:

string type;
int sockfd;
int fd;

socklen_t addr_size;

const char* messageData;

struct sockaddr_in socketServer;
struct sockaddr_in socketClient;
struct sockaddr* clientAddr;
struct sockaddr* serverAddr; 
};   

